
import ast
import re
from random import randint
from string import Template
from typing import Any, List, Union
import jsonpath
from appium.webdriver import WebElement as AppElement
from httpx import Response
from selenium.webdriver.remote.webelement import WebElement
from utils.decorator import write_back
from utils.typeUtil import TypeUtil
from variable import dependent_data
from utils import *

class ApiDependentHandle:

    def __init__(self):
        self.tu = TypeUtil()

    # {变量:获取数据}
    def dependent_data_acquisition_by_dict(self, extract_var: str, return_data: Any) -> Any:
        if extract_var == "" or extract_var is None:
            return

        extract_var = ast.literal_eval(extract_var)
        data_type = type(return_data)

        temp = {}

        if data_type is Response:
            for k, v in extract_var.items():
                if "$." in v:
                    matched_data = jsonpath.jsonpath(return_data.json(), v)
                else:
                    matched_data = re.findall(v, return_data.text)

                try:
                    if k[1] == 0:
                        save_var = matched_data[randint(0, len(matched_data) - 1)]
                    else:
                        save_var = matched_data[0]
                except Exception:
                    save_var = matched_data[0]

                if isinstance(k, tuple):
                    try:
                        # dependent_data[k[0]] = getattr(self.tu, k[2])(save_var)
                        temp[k[0]] = getattr(self.tu, k[2])(save_var)
                    except Exception:
                        # dependent_data[k[0]] = save_var
                        temp[k[0]] = save_var
                else:
                    # dependent_data[k] = save_var
                    temp[k] = save_var

        elif data_type is list:
            try:
                if list(extract_var.keys())[0][1] == 0:
                    save_var = return_data[randint(0, len(return_data) - 1)]
                else:
                    save_var = return_data[0]
            except Exception:
                save_var = return_data[0]

            for k, v in extract_var.items():
                if isinstance(k, tuple):
                    try:
                        # dependent_data[k[0]] = getattr(self.tu, k[2])(save_var[v])
                        temp[k[0]] = getattr(self.tu, k[2])(save_var[v])
                    except Exception:
                        # dependent_data[k[0]] = save_var[v]
                        temp[k[0]] = save_var[v]
                else:
                    # dependent_data[k] = save_var[v]
                    temp[k] = save_var[v]

        dependent_data.update(temp)

        return temp

    # @write_back
    def dependent_data_acquisition(self, var_name: str, need_data: str, random_info: str, forced_type: str,
                                   return_data: Any) -> Any:
        if var_name is None or need_data is None:
            return

        data_type = type(return_data)

        var_name_list = var_name.split(";")
        need_data_list = need_data.split(";")

        if random_info is not None:
            random_info_list = random_info.split(";")

        if forced_type is not None:
            forced_type_list = forced_type.split(";")

        temp = {}

        if data_type is Response:
            for i in range(len(var_name_list)):
                if "$." in need_data:
                    matched_data = jsonpath.jsonpath(return_data.json(), need_data_list[i])
                else:
                    matched_data = re.findall(need_data_list[i], return_data.text)

                try:
                    if random_info_list[i] == "0":
                        save_var = matched_data[randint(0, len(matched_data) - 1)]
                    else:
                        save_var = matched_data[0]
                except Exception:
                    save_var = matched_data[0]

                try:
                    # dependent_data[var_name_list[i]] = getattr(self.tu, forced_type_list[i])(save_var)
                    temp[var_name_list[i]] = getattr(self.tu, forced_type_list[i])(save_var)
                except Exception:
                    # dependent_data[var_name_list[i]] = save_var
                    temp[var_name_list[i]] = save_var

        elif data_type is list:
            try:
                if random_info_list[0] == "0":
                    save_var = return_data[randint(0, len(return_data) - 1)]
                else:
                    save_var = return_data[0]
            except Exception:
                save_var = return_data[0]

            for i in range(len(var_name_list)):
                try:
                    # dependent_data[var_name_list[i]] = getattr(self.tu, forced_type_list[i])(save_var[i])
                    temp[var_name_list[i]] = getattr(self.tu, forced_type_list[i])(save_var[i])
                except Exception:
                    # dependent_data[var_name_list[i]] = save_var[i]
                    temp[var_name_list[i]] = save_var[i]

        dependent_data.update(temp)

        return temp

    def recursive_search_key(self, son_params: Any, is_assert: bool):
        if type(son_params) is dict:
            for k, v in son_params.items():
                if is_assert:
                    try:
                        assert v == dependent_data[k]
                    except KeyError:
                        raise AssertionError

                if v == "" or v is None:
                    son_params[k] = dependent_data[k]

                if type(v) is dict or type(v) is list:
                    self.recursive_search_key(v, is_assert)

        elif type(son_params) is list:
            for i in range(len(son_params)):
                if type(son_params[i]) is dict or type(son_params[i]) is list:
                    self.recursive_search_key(son_params[i], is_assert)

                else:
                    try:
                        son_params[i] = dependent_data[son_params[i]]
                    except Exception:
                        pass

    def dependent_data_assignment(self, incoming_params: str, is_assert: bool) -> Any:
        try:
            params = ast.literal_eval(incoming_params)
        except Exception:
            return

        self.recursive_search_key(params, is_assert)

        return params

    def splice_path_parameter(self, param_type: str, params: str) -> str:
        if param_type == "path":
            final_params = "/"

            param_list = params.split("/")
            for i in range(len(param_list)):
                try:
                    param_list[i] = str(dependent_data[param_list[i]])
                except Exception:
                    pass

            for param in param_list:
                if param_list.index(param) < len(param_list):
                    final_params += param + "/"
                else:
                    final_params += param

        else:
            final_params = "?"

            param_list = params.split("&")
            for j in range(len(param_list)):
                p_list = param_list[j].split("=")
                if p_list[-1] == "" or p_list[-1] is None:
                    p_list[-1] = str(dependent_data[p_list[0]])
                    if j < len(param_list) - 1:
                        final_params += p_list[0] + "=" + p_list[-1] + "&"
                    else:
                        final_params += p_list[0] + "=" + p_list[-1]

        return final_params

    def exec_func(self, func: str) -> str:
        loc = locals()
        exec(f"result = {func}")
        return str(loc['result'])

    def matching_variable(self, incoming_params: str) -> Any:
        incoming_params = Template(incoming_params).safe_substitute(dependent_data)

        funcs = re.findall('\\${(.*?)}', incoming_params)
        for func in funcs:
            incoming_params = incoming_params.replace('${%s}' % func, self.exec_func(func))

        try:
            params = ast.literal_eval(incoming_params)
        except Exception:
            params = incoming_params

        return params

    def new_matching_variable(self, incoming_params: str):
        incoming_params = Template(incoming_params).safe_substitute(dependent_data)
        try:
            params = eval(incoming_params)
        except Exception:
            params = incoming_params

        return params

    def get_display_info(self, v, element):
        if isinstance(v, tuple):
            matched_data = getattr(element, v[0])(v[1])  # element.get_attribute(v)
        else:
            matched_data = getattr(element, v)  # element.text

        return matched_data

    # {预期:实际}
    def result_assertion_by_dict(self, assert_info: str, return_data: Any, element: Union[WebElement, AppElement],
                                 result_map: dict):
        data_type = type(return_data)

        result: dict = {}
        matched_data = None
        # expect = self.matching_variable(assert_info)
        expect = self.new_matching_variable(assert_info)
        for k, v in expect.items():
            try:
                if data_type is Response:
                    if "$." in v:
                        matched_data = jsonpath.jsonpath(return_data.json(), v)[0]
                    else:
                        matched_data = re.findall(v, return_data.text)[0]

                elif data_type is list:
                    matched_data = return_data[0][v]

                if element is not None:
                    matched_data = self.get_display_info(v, element)

            except Exception:
                matched_data = v

            result_map[v] = matched_data
            result[k] = matched_data

            assert matched_data == k

        return result




























































